package com.cscp.javastudy.juc.functionalprogramming.stream;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class AuthorTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();

        /**
         * 打印所有年龄小于18岁作家的名字并去重
         */
//        authors.stream()//把集合转换为流
//                .distinct()//去重
//                .filter(author -> author.getAge()<18)//过滤年龄<18
//                .forEach(author -> System.out.println(author.getName()));//打印名字

        /**
         * filter()
         * 输出名字长度大于4的名字
         */
//        authors.stream()
//                .filter(author -> author.getName().length()>4)
//                .forEach(author -> System.out.println(author.getName()));

        /**
         * map()
         * 输出所有作家的名字
         */
//        authors.stream()
//                .map(author -> author.getName())
//                .forEach(name -> System.out.println(name));

        /**
         * 所有作家的年龄加10
         */
//        authors.stream()
//                .map(author -> author.getAge()+10)
//                .forEach(age -> System.out.println(age));

        /**
         * Array转Stream
         */
//        arrayToStream();

        /**
         * Map转Stream
         */
//        mapToStream();

        /**
         * distinct()
         * 打印所有作家的名字，要求不能有重复元素
         */
//         authors.stream()
//                 .distinct()//底层使用Object的equals()实现的所有要注意重写equals()
//                 .forEach(author -> System.out.println(author.getName()));

        /**
         * sorted() 如果调用了空参的这个方法，需要流中的元素是实现了Comparable接口
         */
//        authors.stream()
//                .distinct()
//                .sorted()
//                .forEach(author -> System.out.println(author.getAge()));

        /**
         * sorted(...) 调用有参的方法
         */
//        authors.stream()
//                .distinct()
//                .sorted((o1, o2) -> o1.getAge()-o2.getAge())//Author类里实现了Comparable接口
//                .forEach(author -> System.out.println(author.getAge()));

        /**
         * limit()
         * 对流中的元素按照年龄进行降序排序，并要求不能有重复的元素，然后打印其中两个年龄最大的作家的年龄
         */
//        authors.stream()
//                .distinct()
//                .sorted()
//                .limit(2)
//                .forEach(author -> System.out.println(author.getAge()));

        /**
         * skip()
         * 打印除了年龄最大的作家外的其他作家，要求不能有重复元素，并且按照年龄降序
         */
//        authors.stream()
//                .distinct()
//                .sorted()
//                .skip(1)
//                .forEach(author -> System.out.println(author.getAge()));

        /**
         * flatMap()
         * 打印所有书籍的名字，要求对重复的元素进行去重
         */
//        authors.stream()
//                .flatMap(author -> author.getBooks().stream())
//                .distinct()
//                .forEach(book -> System.out.println(book.getName()));

        /**
         * flatMap()
         * 打印现有数据的所有分类，要求对分类去重，分类后的格式不允许为：类目1,类目2
         */
//        authors.stream()
//                .flatMap(author -> author.getBooks().stream())
//                .distinct()
//                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
//                .distinct()
//                .forEach(category -> System.out.println(category));


        /**
         * count()
         * 打印这些作家的所出书籍的数目，注意删除重复元素
         */
//        System.out.println(authors.stream()
//                .flatMap(author -> author.getBooks().stream())
//                .distinct()
//                .count());

        /**
         *  max()
         *  min()
         *  分别获取这些作家所有书籍中的最高分和最低分并打印
         */
//        Optional<Integer> min = authors.stream()
//                .flatMap(author -> author.getBooks().stream())
//                .map(book -> book.getScore())
////                .max(((score1, score2) -> score1 - score2));//获取最大值
//                .min(((score1, score2) -> score1 - score2));//获取最小值
//        System.out.println(min.get());

        /**
         * collect()
         * 获取一个存放所有作家名字的list集合
         */
//        List<String> nameList = authors.stream()
//                .map(author -> author.getName())
//                .collect(Collectors.toList());
//        System.out.println(nameList);

        /**
         * collect()
         * 获取一个所有书名的Set集合
         */
//        Set<String> nameSet = authors.stream()
//                .flatMap(author -> author.getBooks().stream())
//                .map(book -> book.getName())
//                .collect(Collectors.toSet());
//        System.out.println(nameSet);

        /**
         * collect()
         * 获取一个map集合，map的key为作者名，value为List<book>
         */
//        Map<String, List<Book>> map = authors.stream()
//                .distinct()
//                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
//        System.out.println(map);

        /**
         * anyMatch()
         * 判断年龄是否有29岁以上的作家
         */
//        System.out.println(authors.stream()
//                .anyMatch(author -> author.getAge()>33));//false


        /**
         * allMatch()
         * 判断所有的作家是否为成年人
         */
//        System.out.println(authors.stream()
//                .allMatch(author -> author.getAge() > 18));//false


        /**
         * noneMatch()
         * 判断作家是否都没有超过100岁
         */
//        System.out.println(authors.stream()
//                .noneMatch(author -> author.getAge() > 100));//false

        /**
         * findAny()
         * 获取任意一个大于18岁的作家，如果存在就输出他的名字
         */
//        Optional<Author> resAuthor = authors.stream()
//                .filter(author -> author.getAge() > 18)
//                .findAny();
//        resAuthor.ifPresent(authorTmp -> System.out.println(authorTmp.getName()));

        /**
         * findFirst()
         * 获取一个年龄最小的作家，并输出他的名字
         */
//        Optional<Author> first = authors.stream()
//                .sorted(((o1, o2) -> o1.getAge() - o2.getAge()))
//                .findFirst();
//        first.ifPresent(author -> System.out.println(author.getAge()));

        /**
         * reduce(param1, param1)
         * 求所有作者年龄的和
         */
//        System.out.println(authors.stream()
//                .distinct()
//                .map(author -> author.getAge())
//                //这步操作类似于sum=0;sum+=element  ->后面是自己定义的计算方式
//                .reduce(0, (result, element) -> result + element));//0为初始值，element为遍历的年龄，result为计算结果

        /**
         * reduce(param1, param1)
         * 求所有作者中的年龄最大值
         */
//        Integer max = authors.stream()
//                .map(author -> author.getAge())
//                .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
//        System.out.println(max);

        /**
         * reduce(param1, param1)
         * 求所有作者中的年龄最小值
         */
//        Integer min = authors.stream()
//                .map(author -> author.getAge())
//                .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
//        System.out.println(min);

        /**
         * reduce(param1) 一个参数的重载形式内部的计算, 这种不需要初始化值
         * 求所有作者中的年龄最小值
         */
//        Optional<Integer> optionalInteger = authors.stream()
//                .map(author -> author.getAge())
//                .reduce((result, element) -> result > element ? element : result);
//        optionalInteger.ifPresent(age -> System.out.println(age));

        /**
         * and() 相当于&&
         * 打印作家中年龄大于17并且长度大于1的作家
         */
//        List<Author> authors1 = getAuthors();
//        authors.stream()
//                .filter(author -> author.getAge()>17 && author.getName().length()>3)
//                .forEach(author -> System.out.println(author.getAge()));

        /**
         * or() 相当于 ||
         * 打印作家中年龄大于17并且长度大于1的作家
         */
//        List<Author> authors1 = getAuthors();
//        authors.stream()
//                .filter(new Predicate<Author>() {
//                    @Override
//                    public boolean test(Author author) {
//                        return author.getName().length()>10;
//                    }
//                }.or(new Predicate<Author>() {
//                    @Override
//                    public boolean test(Author author) {
//                        return author.getAge()>18;
//                    }
//                })).forEach(author -> System.out.println(author.getAge()));

        /**
         * negate() 相当于 !取反
         * 打印作家中年龄不大于17
         */
//        List<Author> authors1 = getAuthors();
//        authors1.stream()
//                .filter(new Predicate<Author>() {
//                    @Override
//                    public boolean test(Author author) {
//                        return author.getAge()>=17;
//                    }
//                }.negate()).forEach(author -> System.out.println(author.getAge()));

        /**
         * stream.parallel()
         * 并行流测试
         */
        testParallelStream();

    }


    private static void testParallelStream(){
        Stream<Integer> stream = Stream.of(1,2,3,4,5,6,7,8,9,10);
        Integer sum = stream.parallel()
                .peek(num -> System.out.println(num + " : " + Thread.currentThread().getName()))
                .filter(num -> num > 5)
                .reduce((result, element) -> result + element)
                .get();
        System.out.println(sum);
    }

    public static void mapToStream(){
        Map<String, Integer> map = new HashMap<>();
        map.put("Jama", 19);
        map.put("Evan", 20);
        map.put("George", 21);

        Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
        stream.filter(entry -> entry.getValue()>19)
                .forEach(entry -> System.out.println(entry.getKey() + " : " + entry.getValue()));
    }

    public static void arrayToStream(){
        Integer[] arr = {1,2,3,4,5};
//        Stream<Integer> stream = Arrays.stream(arr);
        Stream.of(arr)
                .distinct()
                .filter(integer -> integer>2)
                .forEach(integer -> System.out.println(integer));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author1 = new Author(1L, "Jama", 33, "西安人", null);
        Author author2 = new Author(2L, "Gavin", 16, "宝鸡人", null);
        Author author3 = new Author(3L, "Evan", 31, "北京人", null);
        Author author4 = new Author(1L, "Jama", 33, "西安人", null);
        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L, "操作系统","计算机应用", 88, "大学一年级课程"));
        books1.add(new Book(2L, "计算机组成原理","计算机应用", 87, "大学一年级课程"));

        books2.add(new Book(3L, "马哲","哲学", 90, "大学二年级课程"));
        books2.add(new Book(4L, "毛概","哲学", 91, "大学二年级课程"));
        books2.add(new Book(5L, "政治","哲学", 92, "大学二年级课程"));

        books3.add(new Book(5L, "C++","软件编程", 79, "大学三年级课程"));
        books3.add(new Book(6L, "C语言","软件编程", 78, "大学三年级课程"));
        books3.add(new Book(1L, "操作系统","计算机应用", 88, "大学一年级课程"));

        author1.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books1);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author1,author2,author3,author4));

        return authorList;
    }
}
